import { Injectable, CanActivate, ExecutionContext, UnauthorizedException, ForbiddenException, Logger } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { RoleService } from '../../modules/role/role.service';
import { MenuService } from '../../modules/menu/menu.service';

/**
 * 需要的权限装饰器元数据键
 */
export const PERMISSIONS_KEY = 'permissions';

/**
 * 权限守卫 - 用于验证用户是否有权限访问资源
 * 注意：该守卫需要与JwtAuthGuard一起使用，确保请求中有用户信息
 */
@Injectable()
export class PermissionGuard implements CanActivate {
  private readonly logger = new Logger(PermissionGuard.name);

  constructor(
    private reflector: Reflector,
    private roleService: RoleService,
    private menuService: MenuService,
  ) { }

  async canActivate(context: ExecutionContext): Promise<boolean> {
    // 从控制器或方法上获取所需权限
    const requiredPermissions = this.reflector.getAllAndOverride<string[]>(
      PERMISSIONS_KEY,
      [context.getHandler(), context.getClass()],
    );

    // 记录详细的请求信息
    const request = context.switchToHttp().getRequest();
    this.logger.debug(`处理请求: ${request.method} ${request.url}`);
    this.logger.debug(`所需权限: ${JSON.stringify(requiredPermissions)}`);

    // 如果没有设置权限要求，则允许访问
    if (!requiredPermissions || requiredPermissions.length === 0) {
      this.logger.debug('无需权限，允许访问');
      return true;
    }

    const user = request.user;
    this.logger.debug(`用户信息: ${JSON.stringify(user)}`);

    // 必须先通过认证中间件设置user信息
    if (!user) {
      this.logger.warn('用户未认证，请先登录');
      // 这里修改为返回false而不是抛出异常，让JwtAuthGuard处理认证失败
      return false;
    }

    try {
      // 获取用户的角色
      const roles = await this.roleService.getRolesByUserId(user.userId);
      this.logger.debug(`用户角色: ${JSON.stringify(roles)}`);

      if (!roles || roles.length === 0) {
        this.logger.warn(`用户 ${user.userId} 没有分配角色`);
        throw new ForbiddenException('用户没有分配角色，无法访问此资源');
      }

      // 检查用户是否为超级管理员
      const isAdmin = roles.some(role => role.roleKey === 'admin');
      this.logger.debug(`是否超级管理员: ${isAdmin}`);

      // 如果是超级管理员，直接放行
      if (isAdmin) {
        this.logger.debug('超级管理员访问，允许放行');
        return true;
      }

      // 获取用户角色的所有权限（直接从菜单获取权限标识，不查询sys_permission表）
      const roleIds = roles.map(role => role.roleId);
      const permissionKeys = await this.menuService.getUserPermissionKeysByRoleIds(roleIds);
      this.logger.debug(`用户权限: ${JSON.stringify(permissionKeys)}`);

      // 转换为权限对象格式以便兼容现有代码
      const permissions = permissionKeys.map(key => ({ permissionKey: key }));

      // 检查用户是否拥有所需权限
      const hasPermission = this.hasRequiredPermissions(permissions, requiredPermissions);
      this.logger.debug(`权限检查结果: ${hasPermission}`);

      if (!hasPermission) {
        const missingPermissions = this.getMissingPermissions(permissions, requiredPermissions);
        this.logger.warn(`用户 ${user.userId} 权限不足，缺少权限: ${missingPermissions.join(', ')}`);
        throw new ForbiddenException(`权限不足，缺少以下权限: ${missingPermissions.join(', ')}`);
      }

      return true;
    } catch (error) {
      if (error instanceof ForbiddenException) {
        throw error;
      }
      this.logger.error(`权限检查出错: ${error.message}`, error.stack);
      throw new ForbiddenException('权限检查失败，请联系管理员');
    }
  }

  /**
   * 判断用户是否拥有所需权限
   */
  private hasRequiredPermissions(
    userPermissions: any[],
    requiredPermissions: string[]
  ): boolean {
    // 获取用户所有权限的标识符
    const userPermKeys = userPermissions.map(p => p.permissionKey);

    // 检查是否包含所需的所有权限
    return requiredPermissions.every(permission =>
      userPermKeys.includes(permission)
    );
  }

  /**
   * 获取用户缺少的权限列表
   */
  private getMissingPermissions(
    userPermissions: any[],
    requiredPermissions: string[]
  ): string[] {
    const userPermKeys = userPermissions.map(p => p.permissionKey);
    return requiredPermissions.filter(permission => !userPermKeys.includes(permission));
  }
}